home *** CD-ROM | disk | FTP | other *** search
- /*
- * Blob Manager Demonstration: Tower of Hanoi
- *
- * 26 July 1986 Paul DuBois
- */
-
- # include "TransSkel.h"
-
- # include "BlobMgr.h"
- # include "BlobDemo.h"
-
-
- # define xBase 17 /* upper left corner of apparatus base */
- # define yBase 130
- # define baseHeight 12 /* length is computed */
- # define slotHeight 18 /* size of disk slots */
- # define slotWidth 100
- # define slotHGap 20 /* horiz. gap between slots */
- # define slotVGap 0 /* vert. gap between slots */
- # define hExtra 20 /* extra space at ends of base */
- # define nDisks 6 /* number of disks */
- # define postWidth 12 /* height is computed */
-
-
- static WindowPtr wind;
- static BlobSetHandle donors;
- static BlobSetHandle receptors;
- static BlobHandle tower[3][nDisks]; /* induced data structure */
-
-
-
- static void
- DrawApparatus (void)
- {
- short postHeight, baseWidth, h, v, i;
- Rect r;
-
- postHeight = nDisks * (slotHeight + slotVGap) + postWidth/2;
- h = xBase + hExtra + slotWidth/2 - postWidth/2;
- SetRect (&r, h, yBase - postHeight, h + postWidth, yBase+postWidth/2);
-
- for (i = 0; i < 3; ++i)
- {
- FillRoundRect (&r, postWidth, postWidth, gray);
- FrameRoundRect (&r, postWidth, postWidth);
- OffsetRect (&r, slotWidth + slotHGap, 0);
- }
-
- baseWidth = 3 * slotWidth + 2 * slotHGap + 2 * hExtra;
- SetRect (&r, xBase, yBase, xBase + baseWidth, yBase + baseHeight);
- FillRect (&r, dkGray);
- FrameRect (&r);
- }
-
-
- /*
- * If a disk was moved onto a pile, but has empty slots under it,
- * drop it until it can't go any farther.
- */
-
- static void
- DropDisk (void)
- {
- short i, j;
-
- for (i = 0; i < 3; ++i)
- {
- for (j = nDisks - 1; j > 0; --j) /* don't check bottom pos */
- {
- if (BGlob (tower[i][j]) != nil)
- {
- if (BGlob (tower[i][j-1]) == nil)
- TransferGlob (tower[i][j], tower[i][j-1]);
- }
- }
- }
- }
-
-
- static pascal void
- Mouse (Point pt, long t, short mods)
- {
- BlobClick (pt, t, nil, receptors);
- DropDisk ();
- }
-
-
- /*
- * The advisory functions as follows: receptor clicks are checked
- * and if the click isn't in the top disk of a pile, the click is
- * ignored (message advRClick). When a receptor is dragged somewhere
- * else, it must be to a pile in which the disk under it is larger -
- * can't drag onto a smaller disk (message advXfer).
- */
-
- static pascal Boolean
- Advisory (short mesg, BlobHandle b)
- {
- BlobHandle g;
- short index, pile, piece, i;
- static short srcRank;
-
- index = GetBlobIndex (receptors, b);
- pile = index / nDisks; /* 0 .. 2 */
- piece = index % nDisks; /* 0 .. nDisks-1 */
-
- switch (mesg)
- {
- case advRClick:
- {
- if (piece < nDisks - 1 && BGlob (NextBlob (b)) != nil)
- return (false);
- srcRank = GetBRefCon (BGlob (b)); /* rank of dragged piece */
- break;
- }
- case advXfer:
- {
- for (i = 0; i < piece; ++i)
- {
- if ((g = BGlob (tower[pile][i])) != nil)
- {
- if (GetBRefCon (g) > srcRank)
- return (false);
- }
- }
- break;
- }
- }
- return (true);
- }
-
-
- static pascal void
- Update (Boolean resized)
- {
- DrawControls (wind);
- DrawApparatus ();
- DrawBlobSet (receptors);
- }
-
-
- static pascal void
- Activate (Boolean active)
- {
- if (active)
- {
- SetDragRects (wind);
- SetBCPermissions (false, true, false, false, false);
- SetBCAdvisory (Advisory);
- }
- else
- SetBCAdvisory (nil);
- }
-
- /*
- * Call this before calling MakeDonors().
- */
-
- static void
- MakeReceptors (void)
- {
- BlobHandle b;
- Rect r, r2, r3;
- short i, j, h, v;
-
- receptors = NewBlobSet ();
- for (i = 0; i < 3; ++i)
- {
- for (j = 0; j < nDisks; ++j)
- {
- b = NewBlob (receptors, true, 0, false, 0L);
- tower[i][j] = b;
- OpenBlob ();
- SetRect (&r, 0, 0, slotWidth, slotHeight);
- h = slotWidth/2 - postWidth/2;
- SetRect (&r2, h, -1, h + postWidth, slotHeight+1);
- FillRect (&r2, gray); /* fill in post area */
- SetRect (&r3, 0, 0, h, slotHeight); /* erase on sides of post */
- EraseRect (&r3);
- SetRect (&r3, h + postWidth, 0, slotWidth, slotHeight);
- EraseRect (&r3);
- FrameRect (&r2);
- r2 = r;
- InsetRect (&r2, 0, 1);
- CloseRectBlob (b, &r2, &r);
- h = xBase + hExtra + i * (slotWidth + slotHGap);
- v = yBase - (j+1) * (slotHeight + slotVGap);
- MoveBlob (b, inFullBlob, h, v);
- }
- }
- }
-
-
- /*
- * Make donors. These are the pieces that get moved. They're always
- * attached to some receptor, and just float from one receptor to
- * another. The rank of each piece is stored in the reference constant
- * field. The bottom piece is 0, the top is nDisks-1.
- */
-
- static void
- MakeDonors (void)
- {
- short i, j;
- BlobHandle b;
- Rect r, r2;
-
- donors = NewBlobSet ();
- for (i = 0; i < nDisks; ++i)
- {
- b = NewBlob (donors, true, 1, false, (long) i); /* refCon is disk rank */
- OpenBlob ();
- SetRect (&r, 0, 0, slotWidth, slotHeight);
- j = 20 + (nDisks-i-1) * 4;
- SetRect (&r2, slotWidth/2 - j, 1, slotWidth/2 + j, slotHeight-1);
- EraseRect (&r);
- FrameRoundRect (&r2, slotHeight, slotHeight);
- CloseRectBlob (b, &r, &r);
- GlueGlob (b, tower[0][i]); /* glue to first column */
- }
-
- }
-
-
- void
- TohInit (void)
- {
- SkelWindow (wind = GetDemoWind (tohWindRes),
- Mouse, /* mouse clicks */
- nil, /* key clicks */
- Update, /* updates */
- Activate, /* activate/deactivate events */
- nil, /* close window */
- DoWClobber, /* dispose of window */
- nil, /* idle proc */
- false); /* irrelevant, since no idle proc */
-
- MakeReceptors ();
- MakeDonors ();
-
- MakeFrontWind (wind);
- }
-